GraphQL에서 Date 타입 다루기
GraphQL에서는 Date 타입을 기본으로 제공하지 않기 때문에, 서버에서 Date 값을 받아도 실제로는 string으로 처리되는 문제가 발생합니다. 특히 TypeScript 환경에서는 이로 인해 타입 혼란과 런타임 오류가 발생할 수 있습니다. 이 문제를 깔끔하게 해결하는 방법을 소개합니다.
GraphQL에서 Date 타입 문제
scalar DateGraphQL에는 Date가 내장 타입이 아니므로, 커스텀 스칼라로 정의해야 합니다. 이 때문에 클라이언트와 서버 간에 날짜 값이 string 형태로 전달되고, 타입스크립트에서는 이를 Date 타입으로 간주해 혼란이 생깁니다.
const date = useQuery(GET_USER_BIRTH_DATE);
console.log(typeof date);타입스크립트 상으로는 Date처럼 보이지만 실제로는 string이며, 그대로 Date 메서드를 사용하면 오류가 발생합니다.
const date = useQuery(GET_USER_BIRTH_DATE);
console.log(new Date(date));매번 new Date()로 변환하여 사용하면 되는데 이는 번거롭고 비효율적입니다.
GraphQL에서 Date 타입 변환 미들웨어 구현
서버로부터 응답받은 데이터를 자동으로 Date 객체로 변환하는 미들웨어를 구현하면 문제를 해결할 수 있습니다. 이렇게 하면 클라이언트에서는 별도 처리 없이 Date 메서드를 사용할 수 있습니다.
변환이 필요한 쿼리와 필드 선언
먼저, 어떤 쿼리의 어떤 필드를 Date로 변환할지 정의합니다.
const NEEDED_DATE_CONVERT = {
GetUserBirthDate: ["getUserBirthDate.birthDate"],
GetComment: ["getComment.info.createdAt", "getComment.info.updatedAt"],
PaginateUser: ["paginateUser.docs.${index}.birthDate"],
};
const QUERY_LIST = Object.keys(NEEDED_DATE_CONVERT);배열 형태의 응답(docs)은 ${index}를 사용해 모든 인덱스를 처리할 수 있도록 패턴을 정의합니다.
변환 미들웨어 구현
데이터를 평탄화(flatten) 한 후, 지정한 필드를 Date로 변환하고 다시 원래 구조로 복원(unflatten) 합니다. 해당 작업에서는 flat 라이브러리를 사용하기 때문에 설치가 필요합니다.
미들웨어 코드는 간단합니다.
import { flatten, unflatten } from "flat";
const convertDateMiddleware = new ApolloLink((operation, forward) => {
if (DATE_OPERATION_LIST.includes(operation.operationName)) {
return forward(operation).map((response) => {
if (response.data) {
const flattenData: Record<string, any> = flatten(response.data);
const values = DATE_CONVERT_QUERY[operation.operationName];
values.forEach((pattern) => {
// 패턴에 ${index}가 포함되어 있으면 처리
if (pattern.includes("${index}")) {
// 정규 표현식으로 index 부분이 숫자인 경우 찾기
const regex = new RegExp(pattern.replace("${index}", "(\\d+)"));
Object.keys(flattenData).forEach((flatKey) => {
if (regex.test(flatKey) && flattenData[flatKey]) {
flattenData[flatKey] = new Date(flattenData[flatKey]);
}
});
} else {
// 일반적인 키 변환
Object.keys(flattenData).forEach((flatKey) => {
if (flatKey === pattern && flattenData[flatKey]) {
flattenData[flatKey] = new Date(flattenData[flatKey]);
}
});
}
});
const unflattenData = unflatten(flattenData);
if (unflattenData) {
response.data = unflattenData;
}
}
return response;
});
}
return forward(operation);
});${index}를 정규 표현식으로 처리해 배열 내 항목까지 자동 변환하도록 구현했습니다.
결론
이 미들웨어를 사용하면, 서버에서 string으로 전달된 날짜 값을 클라이언트에서 자동으로 Date 객체로 변환해 사용할 수 있습니다. 이제 useQuery나 useLazyQuery를 사용할 때 별도로 날짜를 파싱하지 않아도 되므로, 코드가 훨씬 깔끔하고 안전해집니다.
더 나은 방법이 있다면 의견을 남겨주세요.